/* LIBDGL -- a Directed Graph Library implementation
 * Copyright (C) 2002 Roberto Micarelli
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

/* best view tabstop=4
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <time.h>
#include <errno.h>
#include <ctype.h>

#include "../type.h"
#include "../graph.h"

#include "opt.h"


extern int errno;

#define _EDGESET_OFFSET(pg,pl) ((int)(pl) - (int)(pg)->pEdgeBuffer)

static int _print_node( dglGraph_s * pgraph , dglInt32_t * pnode , void * pvarg )
{
	FILE * f = (FILE*)pvarg;
	dglInt32_t * pedgeset;
	dglInt32_t * pedge;
	dglInt32_t * ptonode;
	dglInt32_t * pnattr;
	int		iAttr, cAttr;
	int		role;
	int		i;
	dglEdgesetTraverser_s edgeaT;

	role = 0;
	if ( dglNodeGet_Status(pgraph,pnode) & DGL_NS_HEAD )
	{
		role |= 1;
	}
	if ( dglNodeGet_Status(pgraph,pnode) & DGL_NS_TAIL )
	{
		role |= 2;
	}

	fprintf( f , "HEAD %-8ld - %-s",
			dglNodeGet_Id(pgraph,pnode),
			(role>2)?"'H/T'":(role==2)?"'T  '":(role==1)?"'H  '":"'A  '");

	if ( (cAttr = dglGet_NodeAttrSize(pgraph)) > 0 ) {
		pnattr = dglNodeGet_Attr(pgraph,pnode);
		fprintf( f , " - HEAD ATTR [" );
		for ( iAttr = 0 ; iAttr < cAttr ; iAttr ++ ) {
			if ( iAttr && !(iAttr%4) ) fprintf( f , " " );
			fprintf( f , "%02x" , ((unsigned char*)pnattr)[iAttr] );
		}
		fprintf( f , "]\n" );
	}
	else {
		fprintf( f , "\n" );
	}

	if ( role & 1 ) {
		pedgeset = dglNodeGet_OutEdgeset(pgraph, pnode);

		dglEdgeset_T_Initialize(&edgeaT, pgraph, pedgeset);
		for	(
			i = 0, pedge = dglEdgeset_T_First( &edgeaT ) ;
			pedge ;
			i++  , pedge = dglEdgeset_T_Next ( &edgeaT )
			)
		{
			ptonode = dglEdgeGet_Tail(pgraph,pedge);

			if ( ptonode ) {
				role = 0;
				if ( dglNodeGet_Status(pgraph,ptonode) & DGL_NS_HEAD )
				{
					role |= 1;
				}
				if ( dglNodeGet_Status(pgraph,ptonode) & DGL_NS_TAIL )
				{
					role |= 2;
				}

				fprintf( f , "EDGE #%-8d: TAIL %-8ld - %-s - COST %-8ld - ID %-8ld",
					 i ,
					 dglNodeGet_Id(pgraph,ptonode) ,
					 (role>2)?"'H/T'":(role==2)?"'T  '":(role==1)?"'H  '":"'A  '",
					 dglEdgeGet_Cost(pgraph,pedge) ,
					 dglEdgeGet_Id(pgraph,pedge)
					 );

				if ( (cAttr = dglGet_NodeAttrSize(pgraph)) > 0 ) {
					pnattr = dglNodeGet_Attr(pgraph,ptonode);
					fprintf( f , " - TAIL ATTR [" );
					for ( iAttr = 0 ; iAttr < cAttr ; iAttr ++ ) {
						if ( iAttr && !(iAttr%4) ) fprintf( f , " " );
						fprintf( f , "%02x" , ((unsigned char*)pnattr)[iAttr] );
					}
					fprintf( f , "]" );
				}

				if ( (cAttr = dglGet_EdgeAttrSize(pgraph)) > 0 ) {
					pnattr = dglEdgeGet_Attr(pgraph,pedge);
					fprintf( f , " - EDGE ATTR [" );
					for ( iAttr = 0 ; iAttr < cAttr ; iAttr ++ ) {
						if ( iAttr && !(iAttr%4) ) fprintf( f , " " );
						fprintf( f , "%02x" , ((unsigned char*)pnattr)[iAttr] );
					}
					fprintf( f , "]\n" );
				}
				else {
					fprintf( f , "\n" );
				}
			}
		}
		dglEdgeset_T_Release( &edgeaT );
	}
	return 0;
}

int main( int argc , char ** argv )
{
	dglGraph_s  	graph;
	int				fd;
	int				nret;

	/* program options
	 */
 	char	*	pszFilein;
 
	GNO_BEGIN/* short  long        default     variable        help */
 	GNO_OPTION( "g", 	"graph", 	NULL ,  	& pszFilein ,	"Graph file to view" )
 	GNO_END
 

	if ( GNO_PARSE( argc , argv ) < 0 )
	{
		return 1;
	}
	/*
	 * options parsed
	 */

	if ( pszFilein == NULL )
	{
		GNO_HELP( "Incomplete parameters" );
		return 1;
	}

	fd = open( pszFilein , O_RDONLY );
	if ( fd < 0 )
	{	
		perror( "open" ); return 1;
	}

	nret = dglRead( & graph , fd );

	if ( nret < 0 )
	{
		fprintf( stderr , "dglRead error: %s\n" , dglStrerror( & graph ) );
		return 1;
	}

	close( fd );

	/* print the header
	 */
	fprintf( stdout , "Version: %d\n" ,
			 graph.Version );
	fprintf( stdout , "Byte Order: %s\n" ,
			 (graph.Endian == DGL_ENDIAN_LITTLE)?"Little Endian":"Big Endian" );
	fprintf( stdout , "Node Attribute Size:  %ld\n" ,
			 graph.NodeAttrSize );
	fprintf( stdout , "Edge Attribute Size:  %ld\n" ,
			 graph.EdgeAttrSize );
	fprintf( stdout , "Counters:  %ld Edges - %ld Nodes: %ld HEAD / %ld TAIL / %ld ALONE\n" ,
			 graph.cEdge , graph.cNode ,
			 graph.cHead , graph.cTail , graph.cAlone );
	fprintf( stdout , "Opaque Settings:\n" );
	fprintf( stdout , "%10ld %10ld %10ld %10ld\n",
			 graph.aOpaqueSet[ 0 ], graph.aOpaqueSet[ 1 ],
			 graph.aOpaqueSet[ 2 ], graph.aOpaqueSet[ 3 ] );
	fprintf( stdout , "%10ld %10ld %10ld %10ld\n",
			 graph.aOpaqueSet[ 4 ], graph.aOpaqueSet[ 5 ],
			 graph.aOpaqueSet[ 6 ], graph.aOpaqueSet[ 7 ] );
	fprintf( stdout , "%10ld %10ld %10ld %10ld\n",
			 graph.aOpaqueSet[ 8 ], graph.aOpaqueSet[ 9 ],
			 graph.aOpaqueSet[ 10 ], graph.aOpaqueSet[ 11 ] );
	fprintf( stdout , "%10ld %10ld %10ld %10ld\n",
			 graph.aOpaqueSet[ 12 ], graph.aOpaqueSet[ 13 ],
			 graph.aOpaqueSet[ 14 ], graph.aOpaqueSet[ 15 ] );
	fprintf( stdout , "Total Cost: %lld\n", graph.nnCost );
	fprintf( stdout , "--\n" );


	{
		dglInt32_t * pnode;
		dglNodeTraverser_s traverser;
		dglNode_T_Initialize( &traverser, &graph );
		for (pnode = dglNode_T_First(&traverser) ; pnode ; pnode = dglNode_T_Next(&traverser)) {
			_print_node( &graph, pnode, stdout );
		}
		dglNode_T_Release   ( & traverser );
	}

	printf( "\n" );
	dglRelease( & graph );
	return 0;

}
